﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Imaging;
using System.IO;
using System.Windows;
using System.Windows.Markup;
using System.Threading;
using System.Windows.Media;

namespace NetAcademia.Web.Mvc.ImageRendering
{
    static class STASlave
    {
        public static ContentWithContentType GeneratePng(string xaml, object data, GeneratedImageFormat imageFormat)
        {
            ContentWithContentType content = new ContentWithContentType();

            //TODO: SmartThreadPool kipróbálása, mert ez így elég veszélyes
            STAParameter p = new STAParameter { Data = data, Xaml = xaml, ImageFormat = imageFormat };
            Thread t = new Thread(load =>
            {
                STAParameter ld = (STAParameter)load;
                ld.Image = GetPng(ld.Xaml, ld.Data, ld.ImageFormat);
            }
            );

#if DEBUG
            System.Diagnostics.Debug.WriteLine(string.Format("GeneratePng on thread: {0}", Thread.CurrentThread.ManagedThreadId));
            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            System.Diagnostics.PresentationTraceSources.DataBindingSource.Switch.Level = System.Diagnostics.SourceLevels.Off;
            watch.Start();
#endif

            t.SetApartmentState(ApartmentState.STA);
            t.Start(p);
            //t.Join(); //TODO: bool sikerult = t.Join(500); az 500 legyen configból és ha nem végez addig a szál (sikerult==false), akkor Abort() ozza meg
            bool success = t.Join(500);
            if (!success)
                t.Abort();
#if DEBUG
            watch.Stop();
            System.Diagnostics.Debug.WriteLine(string.Format("\t{0}ms", watch.ElapsedMilliseconds));
#endif

            var a = t.IsAlive;
            content.ContentType = "image/" + imageFormat.ToString().ToLower();
            content.Bits = p.Image;

            return content;
        }

        //must be on sta thread
        private static byte[] GetPng(string xamlString, object data, GeneratedImageFormat imageFormat)
        {
             
            FrameworkElement xaml;
            BitmapEncoder encoder;

            if (imageFormat == GeneratedImageFormat.Jpeg)
            {
                encoder = new JpegBitmapEncoder();
                ((JpegBitmapEncoder)encoder).QualityLevel = 93;
            }
            else
                encoder = new PngBitmapEncoder();

            xaml = XamlReader.Parse(xamlString) as FrameworkElement;
            xaml.DataContext = data;

            xaml.Arrange(new Rect(0, 0, 1900, 1280));

            try
            {
                xaml.UpdateLayout();
            }
            catch
            {
                xaml.Width = 500;
                xaml.Height = 200;
            }

            //render
            RenderTargetBitmap rtb = new RenderTargetBitmap((int)xaml.ActualWidth + 1, (int)xaml.ActualHeight + 1, 96, 96, PixelFormats.Pbgra32);
            rtb.Render(xaml);
            encoder.Frames.Add(BitmapFrame.Create((BitmapSource)rtb));

            byte[] png;
            using (MemoryStream ms = new MemoryStream())
            {
                encoder.Save(ms);
                ms.Position = 0;
                png = ms.GetBuffer();
            }

            return png;
        }

        class STAParameter
        {
            public string Xaml;
            public object Data; //DataObject
            public GeneratedImageFormat ImageFormat;
            public byte[] Image;
        }
    }


    public enum GeneratedImageFormat
    {
        Png,
        Jpeg
    }
}
